package com.ndphu.comic.gui.activity;

import java.io.IOException;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

import com.ndphu.comic.R;
import com.ndphu.comic.db.DatabaseHelper;
import com.ndphu.comic.gui.fragment.book.OnlineBookChapterListFragment.OnChapterSelectedListener;
import com.ndphu.comic.gui.fragment.book.OnlineBookDetailsFragment;
import com.ndphu.comic.gui.fragment.book.OnlineBookNavigateFragment;
import com.ndphu.comic.gui.fragment.book.OnlineBookNavigateFragment.ChapterNavigationListener;
import com.ndphu.comic.gui.fragment.book.OnlinePageFragment;
import com.ndphu.comic.gui.pager.animation.FlipPageTransformer;
import com.ndphu.comic.io.Utils;
import com.ndphu.comic.io.extend.AsyncTask;
import com.ndphu.comic.io.processor.BookProcessor;
import com.ndphu.comic.io.processor.Manga24hProcessor;
import com.ndphu.comic.io.processor.TruyenTranhTuanProcessor;
import com.ndphu.comic.io.processor.VNSharingProcessor;
import com.ndphu.comic.model.Book;
import com.ndphu.comic.model.Chapter;
import com.ndphu.comic.model.Page;

public class OnlineBook extends FragmentActivity implements OnClickListener, OnPageChangeListener,
		OnChapterSelectedListener, ChapterNavigationListener {

	public static final String PREF_BOOK_DISPLAY = "pref_book_display";
	public static final String PREF_BOOK_DISPLAY_USE_ANIMATION = "pref_book_display_use_animation";
	public static final String PREF_BOOK_DISPLAY_USE_VOLUME_KEY = "pref_book_display_use_volume_key";
	protected static final String TAG = OnlineBook.class.getSimpleName();

	private ViewPager mPager;
	private PagerAdapter mPagerAdapter;
	private String mBookUrl;
	private Book mBook;
	private ActionBar mActionBar;
	private Chapter mChapter = null;
	private ProgressDialog mProgressDialog;
	// public static Map<String, Bitmap> CACHED_BITMAP = new HashMap<String,
	// Bitmap>();
	// public static Map<String, Bitmap> NEXT_PAGE_CACHED = new HashMap<String,
	// Bitmap>();
	private OnlineBookDetailsFragment mOnlineBookDetailsFragment;
	private AsyncTask<String, Void, Book> mLoadBookTask;
	private BookProcessor mBookProcessor;
	private String mBookSource;
	private String mBookCoverUrl;
	private String mBookName;
	private SharedPreferences mRecentBooksPrefs;
	private String mRecentBookListValue;
	private SharedPreferences mBookPref;
	private SharedPreferences mDefaultPref;
	private int mPrefChapter = 0;
	private int mPrefPage = -1;
	private AsyncTask<Void, Integer, Void> mCurrentPageLoadingTask;
	private AsyncTask<Void, Void, Void> mNextPageLoadingTask;
	private DatabaseHelper db;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
		setContentView(R.layout.activity_online_book_reader);
		getActionBar().setDisplayHomeAsUpEnabled(true);

		db = new DatabaseHelper(this);

		mProgressDialog = com.ndphu.comic.gui.utils.Utils.getProgressDialog(this, "Loading", "Loading book's pages",
				true, this);
		mActionBar = getActionBar();
		DisplayMetrics displaymetrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);

		mBookName = getIntent().getStringExtra(MainActivity.EXTRA_BOOK_NAME);
		mBookUrl = getIntent().getStringExtra(MainActivity.EXTRA_BOOK_URL);
		mBookCoverUrl = getIntent().getStringExtra(MainActivity.EXTRA_BOOK_COVER_URL);
		if (mBookCoverUrl == null) {
			mBookCoverUrl = "";
		}
		mBookSource = getIntent().getStringExtra(MainActivity.EXTRA_BOOK_SOURCE);
		System.out.println(mBookSource);

		mRecentBooksPrefs = getSharedPreferences(MainActivity.PREF_RECENT_BOOKS, MODE_APPEND);
		mRecentBookListValue = mRecentBooksPrefs.getString(MainActivity.PREF_RECENT_BOOKS_LIST, "");

		mBookPref = getSharedPreferences(MainActivity.PREF_BOOK, MODE_APPEND);

		mDefaultPref = PreferenceManager.getDefaultSharedPreferences(this);

		String bookPrefJSONStr = mBookPref.getString(mBookUrl, null);
		if (bookPrefJSONStr != null) {
			try {
				JSONObject object = new JSONObject(bookPrefJSONStr);
				mPrefChapter = object.getInt("chapter");
				mPrefPage = object.getInt("page");
			} catch (JSONException e) {
			}
		}

		if (MainActivity.SOURCE_TRUYENTRANHTUAN.equals(mBookSource)) {
			mBookProcessor = new TruyenTranhTuanProcessor();
		} else if (MainActivity.SOURCE_VNSHARING.equals(mBookSource)) {
			mBookProcessor = new VNSharingProcessor();
		} else if (MainActivity.SOURCE_MANGA24H.equals(mBookSource)) {
			mBookProcessor = new Manga24hProcessor();
		}

		if (mBookUrl == null) {
			Toast.makeText(this, "BOOK URL IS NULL", Toast.LENGTH_SHORT).show();
			finish();
		}
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		mActionBar.hide();
		loadBookContent();
	}

	public void loadBookContent() {
		if (this.mBookUrl == null) {
			return;
		}
		mLoadBookTask = new AsyncTask<String, Void, Book>() {
			@Override
			protected void onPreExecute() {
				super.onPreExecute();
				mProgressDialog.setMessage("Preparing chapter list...");
				mProgressDialog.setOnCancelListener(new OnCancelListener() {

					@Override
					public void onCancel(DialogInterface dialog) {
						mLoadBookTask.cancel(true);
					}
				});
				mProgressDialog.show();
			}

			@Override
			protected Book doInBackground(String... params) {
				try {
					return mBookProcessor.prepareOnlineBook(params[0], false);
				} catch (Exception e) {
					e.printStackTrace();
				}
				return null;
			}

			@Override
			protected void onPostExecute(Book result) {
				super.onPostExecute(result);
				mProgressDialog.dismiss();
				if (result == null || result.getChapters() == null || result.getChapters().size() == 0) {
					new AlertDialog.Builder(OnlineBook.this).setTitle("Error")
							.setMessage("Cannot load book data: " + mBookUrl)
							.setPositiveButton("Close", new DialogInterface.OnClickListener() {

								@Override
								public void onClick(DialogInterface dialog, int which) {
									OnlineBook.this.finish();
								}
							}).create().show();
				}
				mBook = result;
				saveToRecentBook();
				initLayout();
			}

			protected void onCancelled() {
				super.onCancelled();
				mProgressDialog.dismiss();
				OnlineBook.this.finish();
			};
		}.execute(this.mBookUrl);
	}

	private void saveToRecentBook() {
		try {
			JSONObject newBook = new JSONObject();
			newBook.put(MainActivity.EXTRA_BOOK_NAME, mBookName);
			newBook.put(MainActivity.EXTRA_BOOK_URL, mBookUrl);
			newBook.put(MainActivity.EXTRA_BOOK_COVER_URL, mBook.getCover());
			newBook.put(MainActivity.EXTRA_BOOK_SOURCE, mBookSource);
			// newBook.put(MainActivity.EXTRA_BOOK_DESC, mBook.getBookDesc());
			JSONArray bookArray = (mRecentBookListValue == null || mRecentBookListValue.trim().length() == 0) ? new JSONArray()
					: new JSONArray(mRecentBookListValue);
			JSONArray newArray = new JSONArray();
			int start = bookArray.length() - MainActivity.NUMBER_OF_RECENT_BOOKS;
			for (int i = (start > 0 ? start : 0); i < bookArray.length(); ++i) {
				JSONObject bookObject = bookArray.getJSONObject(i);
				if (bookObject.has(MainActivity.EXTRA_BOOK_URL)) {
					String url = bookObject.getString(MainActivity.EXTRA_BOOK_URL);
					if (!url.equals(mBookUrl)) {
						newArray.put(bookObject);
					}
				}
			}
			newArray.put(newBook);
			mRecentBooksPrefs.edit().remove(MainActivity.PREF_RECENT_BOOKS_LIST)
					.putString(MainActivity.PREF_RECENT_BOOKS_LIST, newArray.toString()).commit();
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	private void saveBookPref() {
		JSONObject bookPrefJSON = new JSONObject();
		try {
			bookPrefJSON.put("chapter", mBook.findChapterIdx(mChapter.getChapterUrl()));
			bookPrefJSON.put("page", mPager.getCurrentItem());
		} catch (JSONException e) {
			e.printStackTrace();
		}
		mBookPref.edit().remove(mBookUrl).putString(mBookUrl, bookPrefJSON.toString()).commit();
	}

	private void initLayout() {
		// Instantiate a ViewPager and a PagerAdapter.
		this.setTitle(mBook.getName());
		loadBookDetailToSlidingMenu();
		mPager = (ViewPager) findViewById(R.id.pager);
		if (mDefaultPref.getBoolean(OnlineBook.PREF_BOOK_DISPLAY_USE_ANIMATION, false)) {
			mPager.setPageTransformer(true, new FlipPageTransformer());
		}
		mPager.setOnPageChangeListener(this);
		boolean reloadIndex = isRememberPageEnabled();
		if (reloadIndex) {
			SharedPreferences sharedPreferences = getSharedPreferences("page_tracking", Context.MODE_PRIVATE);
			int trackedPage = sharedPreferences.getInt(mBookUrl, 0);
			mPager.setCurrentItem(trackedPage);
		}
		mChapter = mBook.getChapters().get(mPrefChapter);
		loadSelectedChapter();
		updateSelectedChapterToMenu(mPrefChapter);
	}

	private void updateSelectedChapterToMenu(int idx) {
		mOnlineBookDetailsFragment.changeSelectedChapter(idx);
	}

	private void loadBookDetailToSlidingMenu() {
		initSlidingPager();
	}

	private boolean isRememberPageEnabled() {
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
		boolean reloadIndex = prefs.getBoolean("enable_remember_page_index", false);
		return reloadIndex;
	}

	private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
		public ScreenSlidePagerAdapter(FragmentManager fm) {
			super(fm);
		}

		@Override
		public Fragment getItem(int position) {
			if (position == getCount() - 1) {
				OnlineBookNavigateFragment navigationFragment = new OnlineBookNavigateFragment();
				navigationFragment.setOnNextChapterListener(OnlineBook.this);
				navigationFragment.setBook(mBook);
				navigationFragment.setCurrentChapter(mChapter);
				return navigationFragment;
			} else {
				OnlinePageFragment pageFragment = new OnlinePageFragment();
				pageFragment.setUrl(mChapter.getPages().get(position).getLink());
				pageFragment.setPagerAdapter(mPagerAdapter);
				pageFragment.setDatabaseProvider(db);
				return pageFragment;
			}
		}

		@Override
		public int getCount() {
			return mChapter == null ? 0 : (mChapter.getPages().size() + 1);
		}

		@Override
		public float getPageWidth(int position) {
			return super.getPageWidth(position);
		}
	}

	@Override
	protected void onDestroy() {
		if (isRememberPageEnabled()) {
			int currentItem = mPager.getCurrentItem();
			SharedPreferences sharedPreferences = getSharedPreferences("page_tracking", Context.MODE_PRIVATE);
			sharedPreferences.edit().putInt(mBookUrl, currentItem).commit();
		}
		super.onDestroy();
	}

	private void loadSelectedChapter() {
		loadChapterData();
	}

	private void loadChapterData() {
		new AsyncTask<Chapter, Void, List<Page>>() {
			protected void onPreExecute() {
				super.onPreExecute();
				mProgressDialog.setMessage("Preparing pages...");
				mProgressDialog.show();
			};

			@Override
			protected List<Page> doInBackground(Chapter... params) {
				try {
					return mBookProcessor.getChapterPages(params[0].getChapterUrl());
				} catch (IOException e) {
					e.printStackTrace();
				}
				return null;
			}

			protected void onPostExecute(List<Page> result) {
				mProgressDialog.dismiss();
				mChapter.setPages(result);
				mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
				mPager.setAdapter(mPagerAdapter);
				mPager.setCurrentItem(mPrefPage);
				mPrefPage = 0;
				if (mBook != null && mChapter != null) {
					saveBookPref();
				}
				startCurrentPageLoadingDB();
			}

		}.execute(mChapter);
	}

	private void startCurrentPageLoadingDB() {
		if (mCurrentPageLoadingTask != null) {
			mCurrentPageLoadingTask.cancel(true);
		}
		mCurrentPageLoadingTask = new AsyncTask<Void, Integer, Void>() {

			private List<Page> currentPages;
			ProgressDialog pd;

			@Override
			protected void onPreExecute() {
				currentPages = mChapter.getPages();
				pd = new ProgressDialog(OnlineBook.this);
				pd.setTitle("Loading");
				pd.setMessage("Downloading pages...");
				pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
				pd.setCancelable(false);
				pd.setButton(DialogInterface.BUTTON_NEGATIVE, "Stop", new OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						OnlineBook.this.mCurrentPageLoadingTask.cancel(true);
					}
				});
				pd.setCanceledOnTouchOutside(false);
				pd.setMax(currentPages.size());
				pd.show();
			};

			@Override
			protected Void doInBackground(Void... params) {
				if (isCancelled()) {
					return null;
				}
				int loaded = 0;
				for (final Page page : currentPages) {
					if (isCancelled()) {
						return null;
					}
					Log.d(TAG, "Loading bitmap at URL: " + page.getLink());
					byte[] cachedData = db.getCachedPage(page.getLink());
					if (cachedData == null) {
						Log.d(TAG, "Cache not found, start downloading...");
						cachedData = Utils.getRawDataFromURL(page.getLink());
						Log.d(TAG, String.format("Bitmap downloaded, data size = %d", cachedData.length));
						Log.d(TAG, "Adding to database...");
						db.addPageCache(page.getLink(), cachedData);
					} else {
						Log.d(TAG, String.format("Cache hit, data size = %d", cachedData.length));
					}
					Log.d(TAG, "Page bitmap loaded succesfully");
					loaded++;
					this.publishProgress(loaded);
				}
				return null;
			}

			@Override
			protected void onPostExecute(Void result) {
				// Current Page is ready
				if (pd != null) {
					pd.dismiss();
				}
			};

			@Override
			protected void onProgressUpdate(Integer... values) {
				// pd.setMessage(String.format("%d/%d page(s) loaded",
				// values[0], currentPages.size()));
				pd.setProgress(values[0]);
			};

			@Override
			protected void onCancelled() {
				super.onCancelled();

			}

		}.execute();
	}

	// private void startNextPageLoading() {
	// runOnUiThread(new Runnable() {
	//
	// @Override
	// public void run() {
	// Toast.makeText(OnlineBook.this, "Preparing the next page...",
	// Toast.LENGTH_SHORT).show();
	// }
	// });
	// if (mNextPageLoadingTask != null) {
	// mNextPageLoadingTask.cancel(true);
	// }
	// mNextPageLoadingTask = new AsyncTask<Void, Void, Void>() {
	//
	// @Override
	// protected Void doInBackground(Void... params) {
	// int next = mBook.findChapterIdx(mChapter.getChapterUrl()) + 1;
	//
	// if (next < mBook.getChapters().size()) {
	// Chapter nextChapter = mBook.getChapters().get(next);
	// if (isCancelled()) {
	// return null;
	// }
	// try {
	// final List<Page> nextChapterPages =
	// mBookProcessor.getChapterPages(nextChapter.getChapterUrl());
	// for (final Page page : nextChapterPages) {
	// new AsyncTask<Void, Void, Void>() {
	//
	// @Override
	// protected Void doInBackground(Void... params) {
	// String url = page.getLink();
	// Bitmap bm = Utils.getBitmapFromUrl(url, 0, 0);
	// synchronized (NEXT_PAGE_CACHED) {
	// NEXT_PAGE_CACHED.put(url, bm);
	// if (NEXT_PAGE_CACHED.size() == nextChapterPages.size()) {
	// OnlineBook.this.runOnUiThread(new Runnable() {
	//
	// @Override
	// public void run() {
	// Toast.makeText(OnlineBook.this, "Load next chapter completed",
	// Toast.LENGTH_SHORT).show();
	// }
	// });
	// }
	// }
	// return null;
	// }
	//
	// }.execute();
	// }
	// } catch (IOException e) {
	// }
	// }
	// return null;
	// }
	// }.execute();
	// };

	@Override
	public void onClick(DialogInterface dialog, int which) {
		mLoadBookTask.cancel(true);
		this.finish();
	}

	@Override
	public void onPageScrollStateChanged(int arg0) {

	}

	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) {

	}

	public void onPageSelected(int postition) {
		if (mBook != null && mChapter != null) {
			saveBookPref();
		}
	}

	private void initSlidingPager() {
		mOnlineBookDetailsFragment = new OnlineBookDetailsFragment();
		mOnlineBookDetailsFragment.setBook(mBook);
		mOnlineBookDetailsFragment.setOnChapterSelectedListener(this);
		getSupportFragmentManager().beginTransaction().replace(R.id.left_drawer, mOnlineBookDetailsFragment).commit();
	}

	@Override
	public void onChapterSelected(Chapter chapter) {
		this.mChapter = chapter;
		loadSelectedChapter();
	}

	@Override
	public void onNextChapter() {
		performNextChapter();
	}

	private void performNextChapter() {
		int next = mBook.findChapterIdx(mChapter.getChapterUrl()) + 1;
		mChapter = mBook.getChapters().get(next);
		loadSelectedChapter();
		updateSelectedChapterToMenu(next);
	}

	@Override
	public void onPreviousChapter() {
		performPreviousChapter();
	}

	private void performPreviousChapter() {
		int prev = mBook.findChapterIdx(mChapter.getChapterUrl()) - 1;
		mChapter = mBook.getChapters().get(prev);
		loadSelectedChapter();
		updateSelectedChapterToMenu(prev);
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		if (mDefaultPref.getBoolean(PREF_BOOK_DISPLAY_USE_VOLUME_KEY, false)) {
			switch (keyCode) {
			case KeyEvent.KEYCODE_VOLUME_UP:
				if (mPager != null && mPagerAdapter != null) {
					if (mPager.getCurrentItem() < mPagerAdapter.getCount() - 1) {
						mPager.setCurrentItem(mPager.getCurrentItem() + 1, true);
					} else {
						performNextChapter();
					}
				}
				return true;
			case KeyEvent.KEYCODE_VOLUME_DOWN:
				if (mPager != null && mPagerAdapter != null) {
					if (mPager.getCurrentItem() > 0) {
						mPager.setCurrentItem(mPager.getCurrentItem() - 1, true);
					} else {
						performPreviousChapter();
					}
				}
				return true;
			default:
				return super.onKeyUp(keyCode, event);
			}
		} else {
			return super.onKeyUp(keyCode, event);
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (mDefaultPref.getBoolean(PREF_BOOK_DISPLAY_USE_VOLUME_KEY, false)) {
			switch (keyCode) {
			case KeyEvent.KEYCODE_VOLUME_UP:

				return true;
			case KeyEvent.KEYCODE_VOLUME_DOWN:

				return true;
			default:
				return super.onKeyDown(keyCode, event);
			}
		} else {
			return super.onKeyDown(keyCode, event);
		}
	}
}
